package imai78gae.heya.service.impl;

import imai78gae.heya.exception.ParameterInvalidException;
import imai78gae.heya.exception.ResourceNotFoundException;
import imai78gae.heya.exception.ResourcesAlreadyExistException;
import imai78gae.heya.model.Group;
import imai78gae.heya.model.UserInfo;
import imai78gae.heya.service.AccountService;
import imai78gae.heya.util.CheckUtil;
import imai78gae.heya.util.PMF;

import java.util.ArrayList;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;

/**
 * {@link AccountService}の実装クラスです。
 * @author imai78
 *
 */
public class AccountServiceImpl implements AccountService {

	/**
	 * {@inheritDoc}
	 */
	public void createNewAccount(UserInfo userInfo) {
		this.validateUserInfo(userInfo);
		try {
			this.getUserInfo(userInfo.getLoginId());
			throw new ResourcesAlreadyExistException(userInfo.getLoginId() + " is exist.");
		} catch (ResourceNotFoundException e) {
			;
		}
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Transaction tx = pm.currentTransaction();
		tx.begin();
		try {
			pm.makePersistent(userInfo);
			tx.commit();
		} finally {
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public UserInfo getUserInfo(String loginId) {
		this.validateLoginId(loginId);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		return this.getUserInfo(pm, loginId);
	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	UserInfo getUserInfo(PersistenceManager pm, String loginId) {
		this.validateLoginId(loginId);
		Query query = pm.newQuery(UserInfo.class);
		query.setFilter("loginId == loginIdParam");
		query.declareParameters("String loginIdParam");
		List<UserInfo> list = (List<UserInfo>) query.execute(loginId);
		if (list.size() == 0) {
			throw new ResourceNotFoundException("UserInfo is not found.");
		}
		UserInfo result = list.get(0);
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	public UserInfo login(String loginId, String loginPw) {
		this.validateLoginId(loginId);
		this.validateLoginPw(loginPw);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(UserInfo.class);
		query.setFilter("loginId == loginIdParam && loginPw == loginPwParam");
		query.declareParameters("String loginIdParam, String loginPwParam");
		List<UserInfo> list = (List<UserInfo>) query.execute(loginId, loginPw);
		if (list.size() == 0) {
			throw new ResourceNotFoundException("UserInfo is not found.");
		}
		UserInfo result = list.get(0);
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	public void modifyAccount(UserInfo userInfo) {
		this.validateUserInfo(userInfo);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		UserInfo user = this.getUserInfo(pm, userInfo.getLoginId());
		user.setAccountName(userInfo.getAccountName());
		user.setLoginPw(userInfo.getLoginPw());
		Transaction tx = pm.currentTransaction();
		tx.begin();
		try {
			pm.makePersistent(user);
			tx.commit();
		} finally {
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void removeAccount(UserInfo userInfo) {
		this.validateUserInfo(userInfo);
		PersistenceManager pm = PMF.get().getPersistenceManager();
		UserInfo user = this.getUserInfo(pm, userInfo.getLoginId());
		Transaction tx = pm.currentTransaction();
		tx.begin();
		try {
			pm.deletePersistent(user);
			tx.commit();
		} finally {
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@SuppressWarnings("unchecked")
	public List<Group> getJoinedGroup(String loginId) {
		this.validateLoginId(loginId);
		List<Group> result = new ArrayList<Group>();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(Group.class);
		List<Group> groupList = (List<Group>) query.execute();
		for (Group group : groupList) {
			if (loginId.equals(group.getGroupOwnerId())) {
				result.add(group);
			} else {
				List<String> members = group.getMemberLoginIdList();
				for (String member : members) {
					if (loginId.equals(member)) {
						result.add(group);
					}
				}
			}
		}
		return result;
	}

	/**
	 * {@link UserInfo}チェック用メソッドです。
	 * 
	 * @param userInfo チェック対象の{@link UserInfo}
	 */
	private void validateUserInfo(UserInfo userInfo) {
		if (userInfo == null) {
			throw new ParameterInvalidException("userInfo is null.");
		}
		this.validateLoginId(userInfo.getLoginId());
	}

	/**
	 * {@code loginId}チェック用メソッドです、
	 * 
	 * @param loginId チェック対象の{@code loginId}
	 */
	private void validateLoginId(String loginId) {
		if (CheckUtil.isEmpty(loginId)) {
			throw new ParameterInvalidException("loginId is empty.");
		}
	}

	/**
	 * {@code loginPw}チェック用メソッドです、
	 * 
	 * @param loginPw チェック対象の{@code loginPw}
	 */
	private void validateLoginPw(String loginPw) {
		if (CheckUtil.isEmpty(loginPw)) {
			throw new ParameterInvalidException("loginPw is empty.");
		}
	}

}